package com.zeus.core.report;

import com.zeus.common.enums.ZeusAlarmModelEnum;
import com.zeus.common.utils.HttpUtils;
import com.zeus.core.base.AbstractZeusSelfProtection;
import com.zeus.core.context.ZeusContext;
import com.zeus.core.rule.GatherRule;
import com.zeus.core.rule.GatherRuleFactory;
import lombok.Data;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 报告基础抽象类
 *
 * @author f1ybear_wang  2022/3/2 8:42 下午
 */
public abstract class AbstractBaseZeusReportClient extends AbstractZeusSelfProtection implements ZeusReportClient {
    /**
     * 模式
     */
    protected ZeusAlarmModelEnum model;

    /**
     * 聚合规则
     */
    protected GatherRule gatherRule;

    /**
     * HTTP数据
     */
    protected HttpData httpData;

    /**
     * RPC数据
     */
    protected RpcData rpcData;

    /**
     * 追踪ID
     */
    protected String traceId;

    /**
     * 发生时间-时间戳
     */
    protected Long occurrenceTime;

    public AbstractBaseZeusReportClient() {
        this.occurrenceTime = System.currentTimeMillis();
        // 初始化模式，不同模式走不同逻辑
        this.model = ZeusContext.getContext().alarmModel();
        this.gatherRule = GatherRuleFactory.getRule(model);
        this.initHttp();
        this.initRpc();

        try {
            this.traceId = TraceContext.traceId();
        } catch (Throwable ignored) {
        }
    }

    @Override
    public ZeusAlarmModelEnum getModel() {
        return model;
    }

    /**
     * 获取基础请求参数
     *
     * @author f1ybear_wang  2022/2/25 3:51 下午
     */
    protected String getArgs() {
        if (httpData != null) {
            String args = getHttpArgs();
            if (args != null && !args.isEmpty()) {
                return args;
            }
        }
        if (rpcData != null) {
            return getRpcArgs();
        }
        return null;
    }

    /**
     * 解析HTTP
     *
     * @author f1ybear_wang  2022/2/25 3:51 下午
     */
    private void initHttp() {
        try {
            HttpServletRequest request = HttpUtils.getHttpServletRequest();
            if (request == null) {
                return;
            }
            HttpData httpData = new HttpData();
            httpData.setMethod(request.getMethod());
            httpData.setContentType(request.getContentType());
            httpData.setRequestUri(request.getRequestURI());
            httpData.setParameterMap(request.getParameterMap());
            httpData.setIp(HttpUtils.getIpAddress(request));
            this.httpData = httpData;
        } catch (Throwable ignored) {
        }
    }

    /**
     * 解析RPC
     *
     * @author f1ybear_wang  2022/2/25 3:51 下午
     */
    private void initRpc() {
        try {
           //TODO
        } catch (Throwable ignored) {
        }
    }

    /**
     * 获取HTTP请求参数信息
     *
     * @return 请求参数信息
     * @author f1ybear_wang  2022/3/3 2:50 下午
     */
    private String getHttpArgs() {
        if (this.httpData == null) {
            return null;
        }
        String method = this.httpData.getMethod();
        if (method == null || method.isEmpty()) {
            return null;
        }

        Map<String, String[]> paramsMap = httpData.getParameterMap();
        return getJsonForParamMap(paramsMap);
    }

    /**
     * 获取RPC请求参数信息
     * 
     * @return 请求参数信息
     * @author f1ybear_wang  2022/3/3 2:50 下午
     */
    private String getRpcArgs() {
        if (this.rpcData == null) {
            return null;
        }
        final Object[] arguments = this.rpcData.getArguments();
        if (arguments == null || arguments.length == 0) {
            return null;
        }
        return Arrays.stream(arguments).map(String::valueOf).collect(Collectors.joining(","));
    }

    /**
     * 获取参数Map的JSON字符串
     *
     * @param paramsMap 参数Map
     * @return 参数字符串
     */
    private String getJsonForParamMap(Map<String, String[]> paramsMap) {
        int paramSize = paramsMap.size();
        if (paramsMap == null || paramSize == 0) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, String[]> kv : paramsMap.entrySet()) {
            String key = kv.getKey();
            String[] values = kv.getValue();
            if (values == null) {
                // 没有值
                map.put(key, "");
            } else if (values.length == 1) {
                // 一个值
                map.put(key, values[0]);
            } else {
                // 多个值
                map.put(key, values);
            }
        }
        return map.toString();
    }

    /**
     * HTTP数据
     */
    @Data
    protected static class HttpData {
        /**
         * 请求地址
         */
        private String requestUri;
        /**
         * 方法
         */
        private String method;
        /**
         * 内容类型
         */
        private String contentType;
        /**
         * 参数
         */
        private Map<String, String[]> parameterMap;
        /**
         * IP地址
         */
        private String ip;
    }

    /**
     * Rpc数据
     */
    @Data
    protected static class RpcData {
        /**
         * 方法名称
         */
        private String methodName;
        /**
         * 参数
         */
        private Object[] arguments;
        /**
         * 路径
         */
        private String path;
        /**
         * 远端地址
         */
        private String remoteAddress;
        /**
         * 远端应用名称
         */
        private String remoteApplicationName;
    }
}
